/********************************************************************

Write Date: 2011/06/02
Author: Deng Nianchen
>>>> Add class HeapPtr to provide tranditional smart point utility.

*********************************************************************/
#ifndef HEAP_PTR_HPP
#define HEAP_PTR_HPP
#include "PtrBase.hpp"



_OOPUTILS_BEGIN


/**************************************************************************************************
 * <summary> Purpose: Encapsulate C/C++ pointer so the programmers
 * 					 didn't need to worry whether the content allocated by
 * 					 new operator has been deleted or not. 
 * 					 Usage: Construct a Ptr object with a pointer points to 
 * 					 an object on heap. Then you can use it just like normal 
 * 					 C/C++ pointer. Operators like "->", "*" is supported. 
 * 					 the pointer is also copyable. If you do not want to use it 
 * 					 and want to release the memory manually, simply assign 
 * 					 NULL to it. The memory will be recycled when there are 
 * 					 no pointers pointing to it. 
 * 					 NOTE: You should not construct a HeapPtr using 
 * 					 1. a invalid pointer;
 * 					 2. a pointer point to array;
 * 					 2. a pointer point to content in running stack; 
 * 					 3. a pointer whose content is allocated by malloc function. 
 * 					 Or you will meet unpredictable result like runtime error.
 * 					 Please use OOPPtr for OOPObject objects.
 * 					 Thread-Safe: the class is not thread-safe. </summary>
 * 
 * <remarks>  Deng Nianchen, 2011/06/02. </remarks>
 **************************************************************************************************/

template< class _Ty >
class HeapPtr : public PtrBase< _Ty >
{

    typedef HeapPtr< _Ty > _My;

private:

    uint * _pRefNum;



    void _refIncr ();

    void _refDecr ();

    void _tryRelease ();

public:

    HeapPtr ();

    HeapPtr (_Ty * const newPtr);

    HeapPtr (const _My & right);



    template< class _Ty2 >
    HeapPtr< _Ty2 > cvt () const;

    virtual _My & operator= (const _My & right);

};




/************************************************************************/
/* Constructors & Destructor                                            */
/************************************************************************/



template< class _Ty >
HeapPtr< _Ty >::HeapPtr () : PtrBase< _Ty > (NULL), _pRefNum (NULL) {}



template< class _Ty >
HeapPtr< _Ty >::HeapPtr (_Ty* const newPtr) : PtrBase< _Ty > (newPtr), 
        _pRefNum (newPtr ? new uint () : NULL)
{
    _refIncr ();
}



template< class _Ty >
HeapPtr< _Ty >::HeapPtr (const HeapPtr< _Ty >& right) 
    : PtrBase< _Ty > (right.__pObj), _pRefNum (right._pRefNum)
{
    _refIncr ();
}



/************************************************************************/
/* Assignment Function                                                  */
/************************************************************************/



template< class _Ty >
HeapPtr< _Ty > & HeapPtr< _Ty >::operator= (const HeapPtr< _Ty > & right)
{
    _refDecr ();
    __pObj = right.__pObj;
    _pRefNum = right._pRefNum;
    _refIncr ();
    return *this;
}



/************************************************************************/
/* Convert Function                                                     */
/************************************************************************/



template< class _Ty >
template< class _Ty2 >
HeapPtr< _Ty2 > HeapPtr< _Ty >::cvt () const
{
    Ty2 * pObjCvted = dynamic_cast< OOPObject * > (__pObj);
    if (pObjCvted == NULL) {
        TypeConvertFailException e (typeid(_Ty *).name (),
                typeid(_Ty2 *).name ());
        OOPTHROW_A (e, TypeConvertFailException);
    }
    HeapPtr< _Ty2 > ptrRet (pObjCvted, _pRefNum);
    return ptrRet;
}



/************************************************************************/
/* Private Functions                                                    */
/************************************************************************/



template< class _Ty >
void HeapPtr< _Ty >::_tryRelease ()
{
    if (_ptr && (!_pRefNum || (_pRefNum && (*_pRefNum) == 0)))
    {
        delete _ptr;
        delete _pRefNum;
    }
}



template< class _Ty >
void HeapPtr< _Ty >::_refIncr ()
{
    if (_pRefNum)
    {
        ++(*_pRefNum);
    }
}



template< class _Ty >
void HeapPtr< _Ty >::_refDecr ()
{
    if (_pRefNum)
    {
        --(*_pRefNum);
        _tryRelease ();
    }
    _pRefNum = NULL;
    __pObj = NULL;
}



_OOPUTILS_END



#endif